var Rope = {
  attachBlock : function(entity, x, y, z, len) {
    var id = this.id++;
    this.rope[id] = {
      type : 0,
      target : entity,
      x : x,
      y : y,
      z : z,
      len : len
    };
    return id;
  },
  
  attachEntity : function(entity1, entity2, len, isStatic) {
    var id = this.id++;
    this.rope[id] = {
      type : (isStatic ? 1 : 2),
      target : parseInt(entity1),
      entity : parseInt(entity2),
      len : len
    };
    return id;
  },
  
  detach : function(id) {
    if (id == null) {
      this.rope = {};
    } else {
      delete this.rope[id];
    }
  },
  
  freeEntity : function(entity) {
    var i;
    for (i in this.rope) {
      c = this.rope[i];
      if (c.target == entity || c.type == 2 && c.entity == entity) delete this.rope[i];
    }
  },
  
  freeBlock : function(x, y, z) {
    var i;
    for (i in this.rope) {
      c = this.rope[i];
      if (c.type == 0 && c.x == x && c.y == y && c.z == z) delete this.rope[i];
    }
  },
  
  getLength : function(id) {
    if (!(id in this.rope)) return NaN;
    return this.rope[id].len;
  },
  
  setLength : function(id, len) {
    if (!(id in this.rope)) return NaN;
    return this.rope[id].len = len;
  },
  
  addLength : function(id, val) {
    if (!(id in this.rope)) return NaN;
    return this.rope[id].len += val;
  },
  
  getDistance : function(id) {
    var c, p, o;
    if (!(id in this.rope)) return NaN;
    c = this.rope[id];
    p = [Entity.getX(c.target), Entity.getY(c.target), Entity.getZ(c.target)];
    if (c.type == 0) {
      o = [p[0] - c.x, p[1] - c.y, p[2] - c.z];
    } else {
      o = [p[0] - Entity.getX(c.entity), p[1] - Entity.getY(c.entity), p[2] - Entity.getZ(c.entity)];
    }
    return Math.sqrt(o[0] * o[0] + o[1] * o[1] + o[2] * o[2]);
  },
  
  exists : function(id) {
    return id in this.rope;
  },
  
  load : function() {
    if (!(new java.io.File(this.WORLD_DIR + Level.getWorldDir() + "/.Rope.xero")).exists()) {
      this.id = 0;
      this.rope = {};
      return;
    }
    var rd = new java.io.BufferedReader(new java.io.FileReader(this.WORLD_DIR + Level.getWorldDir() + "/.Rope.xero"));
    var s = [], ln, r;
    while (ln = rd.readLine()) s.push(ln);
    rd.close();
    r = JSON.parse(s.join("\n"));
    this.id = r.id;
    this.rope = r.xero;
  },
  
  save : function() {
    var wr = new java.io.FileOutputStream(this.WORLD_DIR + Level.getWorldDir() + "/.Rope.xero");
    if (Object.keys(this.rope).length == 0) this.id = 1;
    wr.write(new java.lang.String(JSON.stringify({
      id : this.id,
      xero : this.rope
    })).getBytes());
    wr.close();
  },
  
  showRope : function(id) {
    this.visibkeRope = parseInt(id);
  },
  
  calcVel : function() {
    var i, c, p, o, d;
    this.onTick(); //modified
    for (i in this.rope) {
      c = this.rope[i];
      p = [Entity.getX(c.target), Entity.getY(c.target), Entity.getZ(c.target)];
      if (p[1] <= 0) {
        delete this.rope[i];
        continue;
      }
      if (c.type == 0) {
        o = [p[0] - c.x, p[1] - c.y, p[2] - c.z];
      } else {
        if (Entity.getY(c.entity) <= 0) {
          delete this.rope[i];
          continue;
        }
        o = [p[0] - Entity.getX(c.entity), p[1] - Entity.getY(c.entity), p[2] - Entity.getZ(c.entity)];
        this.calcFall(c.entity); //modified
      }
      this.calcFall(c.target); //modified
      d = (c.len / Math.sqrt(o[0] * o[0] + o[1] * o[1] + o[2] * o[2]) - 1) * this.bounce;
      if (d >= 0) return;
      o[0] *= d; o[1] *= d; o[2] *= d;
      Entity.setVelX(c.target, Entity.getVelX(c.target) + o[0]);
      Entity.setVelY(c.target, Entity.getVelY(c.target) + o[1]);
      Entity.setVelZ(c.target, Entity.getVelZ(c.target) + o[2]);
      this.preventFall(c.target); //modified
      if (i == this.visibleRope && typeof this.particle == "number") Level.addParticle(this.particle, p[0], p[1], p[2], o[0] * 10, o[1] * 10, o[2] * 10, this.particleParam); // modified
      if (c.type == 2) {
        Entity.setVelX(c.entity, Entity.getVelX(c.entity) - o[0]);
        Entity.setVelY(c.entity, Entity.getVelY(c.entity) - o[1]);
        Entity.setVelZ(c.entity, Entity.getVelZ(c.entity) - o[2]);
        this.preventFall(c.entity); //modified
      }
    }
  },
  bounce : 0.02,
  particle : ParticleType.flame,
  particleParam : 1,
  WORLD_DIR : android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/games/com.mojang/minecraftWorlds/",
  rope : {},
  visibleRope : NaN,
  id : 1,
  
  falldist : {},
  clearbl : [],
  webid : 0,
  calcFall : function(entity) {
    var t = this.falldist[entity], l = Entity.getY(entity);
    if (t == undefined) {
      this.falldist[entity] = {
        last : l,
        fall : 0
      };
      return;
    }
    if (t.last > l) t.fall += t.last - l;
    t.last = l;
  },
  preventFall : function(entity) {
    var t = this.falldist[entity];
    if (t == undefined) return;
    if (t.fall > 3) {
      t.fall = 0;
      this.clearbl.push(t = {
        x : Math.floor(Entity.getX(entity)),
        y : Math.floor(Entity.getY(entity)) - 1,
        z : Math.floor(Entity.getZ(entity)),
        velx : Entity.getVelX(entity),
        vely : Entity.getVelY(entity),
        velz : Entity.getVelZ(entity),
      });
      t.id = Level.getTile(t.x, t.y, t.z);
      t.data = Level.getData(t.x, t.y, t.z);
      Level.setTile(t.x, t.y, t.z, this.webid, 0);
    }
  },
  onTick : function() {
    var i, t;
    for (i in this.clearbl) {
      t = this.clearbl[i];
      Entity.setVelX(t.velx);Entity.setVelY(t.vely);Entity.setVelZ(t.velz);
      Level.setTile(t.x, t.y, t.z, t.id, t.data);
    }
    if (this.clearbl.length != 0) this.clearbl.length = 0;
  },

  attachable : {
    "85"  : "木桩",
    "113" : "地狱桩",
    "131" : "钩子",
    "139" : "石柱",
    "145" : "铁砧"
  },
  ropeid : 341,
  deflen : 5,
  gui : null,
  guistate : 0,
  speed : 0,
  pr
  
  newLevel : function() {
    this.load();
    print("绳索 V2.0 DEMO\nGUI：Kingsmem诺言菌丶\nRope库作者：ProjectXero\n整合：ProjectXero\n发布：Kingsmem诺言菌丶");
    print("用史莱姆球点击木桩或实体即可将玩家连接到该木桩或实体上，再次点击即可解开。");
    print("向左划动屏幕右侧的进度条可收缩绳索，向右滑则为释放。");
  },
  
  leaveGame : function() {
    this.save();
  },
  
  useItem : function(x, y, z, itemid, blockid, side, itemDamage, blockDamage) {
    var t;
    if (this.guistate == 1 || !(blockid in this.attachable)) return;
    t = this.attachBlock(Player.getEntity(), x, y, z, 0);
    this.setLength(t, this.getDistance(t) + this.deflen);
    ModPE.showTipMessage("绳索已连接");
  },
  
  attackHook : function(attacker, victim) {
    var t;
    if (this.guistate != 1 || attacker != Player.getEntity()) return;
    preventDefault();
    t = this.attachEntity(attacker, victim, 0);
    this.setLength(t, this.getDistance(t) + this.deflen);
    ModPE.showTipMessage("绳索已连接");
  },
  
  shootGui : function() {
    this.guistate = 1;
  },
  
  sliderGui : function() {
    this.guistate = 2;
  },
  
  hideGui : function() {
    this.guistate = 0;
  },
  
  modTick : function() {
    this.calcVel();
    switch (this.guistate) {
      case 0: //No Gui
      if (Player.getCarriedItem() == this.ropeid) if (Player.getCarriedItemData() == 0) {
        shootGui();
      } else {
        sliderGui();
        fcr
      }
      break;
      case 1: //Shoot Gui
      
      break;
      case 2: //Slider Gui
      
    }
  }
};

/*
var wid = 
var hei = ctx.getWindowManager().getDefaultDisplay().getHeight();

function initGuiApi() {
  var r = {
    ctx : com.mojang.minecraftpe.MainActivity.currentMainActivity.get()
  }, t = r.ctx.getResources().getDisplayMetrics();
  r.Screen = {
    density : t.density,
    width : t.widthPixels,
    height : t.heightPixels
  };
  r.PopupWindow = function(o) {
    if
  }
  r.button = function(
  return r;
}
var GuiApi = initGuiApi();
*/

function uithread(f, args) {
  ctx.runOnUiThread(new java.lang.Runnable({run : function() {try {
    f.apply(null, args);
  } catch(e) {print(e + "\n" + e.stack)}}}));
}

try {
  ctx.setTheme(android.R.style.Theme_Material_Light);
} catch (e) {}
